namespace groopServer.Common.Persistence {
    using System.Web;
    using NHibernate;
    using NHibernate.Cfg;

    public class HybridSessionBuilder : ISessionBuilder {
        public const string NHibernateConfigFilename = @"nhibernate.config";
        private static ISession _currentSession;
        private static ISessionFactory _sessionFactory;

        #region ISessionBuilder Members

        public ISession GetSession() {
            ISessionFactory factory = getSessionFactory();
            ISession session = getExistingOrNewSession(factory);
            return session;
        }

        public Configuration GetConfiguration() {
            var configuration = new Configuration();
            string filePath = GetConfigFilePath();
            configuration.Configure(filePath);
            return configuration;
        }

        #endregion

        private static string GetConfigFilePath() {
            return ConfigFileFinder.GetConfigFilePath("nhibernate", NHibernateConfigFilename);
        }

        private ISessionFactory getSessionFactory() {
            if (_sessionFactory == null) {
                Configuration configuration = GetConfiguration();
                _sessionFactory = configuration.BuildSessionFactory();
            }

            return _sessionFactory;
        }

        private ISession getExistingOrNewSession(ISessionFactory factory) {
            if (HttpContext.Current != null) {
                ISession session = GetExistingWebSession();
                if (session == null) {
                    session = openSessionAndAddToContext(factory);
                } else if (!session.IsOpen) {
                    session = openSessionAndAddToContext(factory);
                }

                return session;
            }

            if (_currentSession == null) {
                _currentSession = factory.OpenSession();
            } else if (!_currentSession.IsOpen) {
                _currentSession = factory.OpenSession();
            }

            return _currentSession;
        }

        public ISession GetExistingWebSession() {
            return HttpContext.Current.Items[GetType().FullName] as ISession;
        }

        private ISession openSessionAndAddToContext(ISessionFactory factory) {
            ISession session = factory.OpenSession();
            HttpContext.Current.Items.Remove(GetType().FullName);
            HttpContext.Current.Items.Add(GetType().FullName, session);
            return session;
        }
    }
}